﻿#ifndef __SBCSP_H__
#define __SBCSP_H__

#if _MSC_VER
#pragma once
#endif

#include "sbcs.h"

K_EXTERN_C_BEGIN

//////////////////////////////////////////////////////////////////////////
// xml

/** ml unit. */
typedef struct kMlu kMlu;

/** ml tag. */
typedef struct kMlTag
{
	char*				name;
	char*				cntx;

	kint				nlen;
	kint				clen;
	kint				line;

#if _SB_WINDOWS_
	// only for windows & debug. not for use
	kwchar*			uname;
	kwchar*			ucntx;
#endif
} kMlTag;

// ml unit
KAPI kMlu* k_mlu_new(void);
KAPI kMlu* k_mlu_new_file(const char* filename);
KAPI kMlu* k_mlu_new_file_l(const kwchar* filename);
KAPI kMlu* k_mlu_new_buffer(kconstpointer data, kint size);
KAPI void k_mlu_delete(kMlu* self);

KAPI void k_mlu_clean_tags(kMlu* self);
KAPI void k_mlu_clean_errs(kMlu* self);
KAPI kcham k_mlu_load_buffer(kMlu* self, kconstpointer data, kint size);
KAPI kcham k_mlu_write_file(kMlu* self, const char* filename);

KAPI kint k_mlu_get_count(kMlu* self);
KAPI const char* k_mlu_get_filename(kMlu* self);
KAPI const char* k_mlu_get_err(kMlu* self, kint at);
KAPI kMlTag* k_mlu_get_tag(kMlu* self, const char* name);
KAPI kMlTag* k_mlu_get_tag_nth(kMlu* self, kint at);
KAPI const char* k_mlu_get_context(kMlu* self, const char* name, const char* ifnotexist K_P(NULL));
KAPI const char* k_mlu_get_context_nth(kMlu* self, kint at, const char* ifnotexist K_P(NULL));
KAPI kint k_mlu_contains(kMlu* self, kMlTag* tag);

KAPI void k_mlu_foreach(kMlu* self, void(*func)(kpointer userdata, kMlTag* tag), kpointer userdata);
KAPI void k_mlu_loopeach(kMlu* self, void(*func)(kMlTag* tag));

KAPI kMlTag* k_mlu_add(kMlu* self, const char* name, const char* context, kint line);
KAPI kMlTag* k_mlu_add_tag(kMlu* self, kMlTag* tag);
KAPI kint k_mlu_remove(kMlu* self, const char* name, kcham isall K_P(TRUE));
KAPI kcham k_mlu_remove_nth(kMlu* self, kint at);
KAPI kcham k_mlu_remove_tag(kMlu* self, kMlTag* tag, kcham isdelete K_P(TRUE));

KAPI void k_mlu_add_err(kMlu* self, const char* msg);
KAPI void k_mlu_add_errf(kMlu* self, const char* fmt, ...);
KAPI void k_mlu_print_err(kMlu* self);

KAPI void k_mlu_print(kMlu* self);

// tag
KAPI kMlTag* k_mltag_new(const char* name);
KAPI void k_mltag_delete(kMlTag* self);

// tag - context
KAPI void k_mltag_add_context(kMlTag* ptr, const char* cntx, kint size);
KAPI void k_mltag_set_context(kMlTag* ptr, const char* cntx, kint size);

// tag - sub
KAPI kint k_mltag_get_sub_count(kMlTag* ptr);
KAPI kMlTag* k_mltag_get_sub(kMlTag* ptr, const char* name);
KAPI kMlTag* k_mltag_get_sub_nth(kMlTag* ptr, kint at);
KAPI const char* k_mltag_get_sub_context(kMlTag* ptr, const char* name, const char* ifnotexist K_P(NULL));
KAPI const char* k_mltag_get_sub_context_nth(kMlTag* ptr, kint at, const char* ifnotexist K_P(NULL));
KAPI kint k_mltag_contains_sub(kMlTag* ptr, kMlTag* tag);
KAPI kMlTag* k_mltag_add_sub(kMlTag* ptr, const char* name, const char* context, kint line);
KAPI kMlTag* k_mltag_add_sub_tag(kMlTag* ptr, kMlTag* tag);
KAPI kint k_mltag_remove_sub(kMlTag* ptr, const char* name, kcham isall K_P(TRUE));
KAPI kcham k_mltag_remove_sub_nth(kMlTag* ptr, kint at);
KAPI kcham k_mltag_remove_sub_tag(kMlTag* ptr, kMlTag* tag, kcham isdelete K_P(TRUE));

KAPI void k_mltag_foreach_sub(kMlTag* ptr, void(*func)(kpointer userdata, kMlTag* tag), kpointer userdata);
KAPI void k_mltag_loopeach_sub(kMlTag* ptr, void(*func)(kMlTag* tag));

// tag - arg
KAPI kint k_mltag_get_arity(kMlTag* ptr);
KAPI const char* k_mltag_get_arg(kMlTag* ptr, const char* name, const char* ifnotexist K_P(NULL));
KAPI kcham k_mltag_next_arg(kMlTag* ptr, kpointer* index, const char** name, const char** data);
KAPI kcham k_mltag_contains_arg(kMlTag* ptr, const char* name);

KAPI void k_mltag_foreach_arg(kMlTag* ptr, void(*func)(kpointer userdata, const char* name, const char* data), kpointer userdata);
KAPI void k_mltag_loopeach_arg(kMlTag* ptr, void(*func)(const char* name, const char* data));

KAPI void k_mltag_set_arg(kMlTag* ptr, const char* name, const char* value);
KAPI kcham k_mltag_remove_arg(kMlTag* ptr, const char* name);


//////////////////////////////////////////////////////////////////////////
// module

/** load information. */
typedef struct kModule
{
	char*				filename;
	kint				ref;
} kModule;

// flags
#define KMDB_LAZY						0x0001					/** 모듈 플래그: LAZY */
#define KMDB_LOCAL						0x0002					/** 모듈 플래그: LOCAL */
#define KMDB_MASK						(KMDB_LAZY|KMDB_LOCAL)	/** 모듈 플래그: LAZY, LOCAL */

#define KMDB_EXT_INFO					0x2000					/** 모듈 상태: 정보 있음 */
#define KMDB_EXT_NOCLOSURE				0x4000					/** 모듈 상태: 닫기 기능 없음 */
#define KMDB_EXT_RESIDENT				0x8000					/** 모듈 상태: 항상 상주 */

// callback
typedef kcham(*kModInitFunc)(kModule*, kpointer, const char**);	/** 모듈이 읽을 때 콜백 */
typedef void(*kModDispFunc)(kModule*);							/** 모듈이 해제될 때 콜백 */

// global
KAPI kcham k_mod_set_suffix(const char* suffix);
KAPI void k_mod_set_error(const char* error);
KAPI const char* k_mod_get_error(void);

// 
KAPI kModule* k_mod_open(const char* filename, kpointer data K_P(NULL), kint flags K_P(0));
KAPI kcham k_mod_close(kModule* self);
KAPI kcham k_mod_sym_ptr(kModule* self, const char* name, kpointer* ptr);
KAPI kcham k_mod_sym_func(kModule* self, const char* name, kfunc* func);
KAPI kint k_mod_ref(kModule* self);
KAPI const char* k_mod_get_name(kModule* self);
KAPI kpointer k_mod_get_handle(kModule* self);


//////////////////////////////////////////////////////////////////////////
// win32 registry
#if _SB_WINDOWS_DESKTOP_
/** Defines an alias representing registry. */
typedef struct kRegistry				kRegistry;

KAPI kRegistry* k_regi_new(const char* container, const char* name, kcham canwrite K_P(FALSE));
KAPI void k_regi_delete(kRegistry* key);
KAPI kcham k_regi_enum(kRegistry* key, kint index, char* buffer, kint size);
KAPI kcham k_regi_query_type(kRegistry* key, const char* name, kint* rettype, kint* retsize);
KAPI kbyte* k_regi_get_unknown(kRegistry* key, const char* name, kint* rettype, kint* retsize);
KAPI kbyte* k_regi_get_binary(kRegistry* key, const char* name, kint* retsize);
KAPI kchar* k_regi_get_multi_string(kRegistry* key, const char* name, kint* retsize);
KAPI kcham k_regi_get_string(kRegistry* key, const char* name, char* buffer, kint size);
KAPI kcham k_regi_get_int(kRegistry* key, const char* name, kint* value);
KAPI kcham k_regi_get_long(kRegistry* key, const char* name, klong* value);
#endif


//////////////////////////////////////////////////////////////////////////
// thread

// callback
typedef kpointer(*kThreadFunc)(kpointer);			/** 스레드 콜백 */
typedef void(*kNotifyFunc)(kpointer);				/** 알림 콜백 */
typedef void(*kResultFunc)(kpointer, kint, kint);	/** 결과 콜백{userdata(result), code, bytes} */
typedef kint(*kIntervalFunc)(kpointer, kint);		/** 인터벌 콜백 */

// type
typedef struct kMutex kMutex;						/** 뮤텍스 */
typedef struct kCond kCond;							/** 조건 */
typedef struct kSem kSem;							/** 세마포어 */
typedef struct kTls kTls;							/** TLS */
typedef struct kThread kThread;						/** 스레드 */

/** once. */
typedef struct kOnce
{
	volatile kint		status;
	volatile kpointer	value;
} kOnce;

KAPI kpointer k_once_run(kOnce* self, kThreadFunc func, kpointer data);
KAPI kcham k_once_enter(volatile kuintptr* value);
KAPI void k_once_leave(volatile kuintptr* value, kuintptr init);

#define k_once_try(value)		(k_atomget_ptr(value) != 0 ? FALSE : k_once_enter(value))

// mutex, basic overlapped lock
KAPI kMutex* k_mutex_new(void);
KAPI kMutex* k_mutex_new_count(kint count);
KAPI void k_mutex_delete(kMutex* self);
KAPI void k_mutex_enter(kMutex* self);
KAPI void k_mutex_leave(kMutex* self);

// condition
KAPI kCond* k_cond_new(void);
KAPI void k_cond_delete(kCond* self);
KAPI void k_cond_signal(kCond* self);
KAPI void k_cond_broadcast(kCond* self);
KAPI void k_cond_wait(kCond* self, kMutex* enterlock);
KAPI kcham k_cond_wait_for(kCond* self, kMutex* enterlock, kint milliseconds);

// semaphore
KAPI kSem* k_sem_new(kint initial);
KAPI void k_sem_delete(kSem* self);
KAPI kcham k_sem_wait(kSem* self);
KAPI kcham k_sem_wait_for(kSem* self, kint milliseconds);
KAPI kcham k_sem_try_wait(kSem* self);
KAPI kcham k_sem_post(kSem* self);
KAPI kint k_sem_value(kSem* self);

// tls
KAPI kTls* k_tls(kNotifyFunc func);
KAPI void k_settls(kTls* self, kpointer value);
KAPI kpointer k_gettls(kTls* self);

// thread
KAPI kThread* k_thread_try(void);
KAPI kThread* k_thread_self(void);
KAPI kcham k_thread_run(kThreadFunc func, kpointer userdata, kuint stacksize K_P(0), kuint busytype K_P(0));
KAPI void k_thread_exit(kpointer ret);

KAPI kThread* k_thread_new(kThreadFunc func, kpointer userdata, kuint stacksize K_P(0), kuint busytype K_P(0));
KAPI void k_thread_delete(kThread* self);
KAPI kcham k_thread_start(kThread* self);
KAPI kpointer k_thread_wait(kThread* self);
KAPI kcham k_thread_set_busy(kThread* self, kint busytype);
KAPI kcham k_thread_set_stack(kThread* self, kuint stacksize);
KAPI kcham k_thread_set_cb(kThread* self, kThreadFunc func, kpointer data);
KAPI kcham k_thread_can_wait(kThread* self);
KAPI kint k_thread_get_busy(kThread* self);
KAPI kuint k_thread_get_stack(kThread* self);
KAPI kuint k_thread_get_id(kThread* self);

K_EXTERN_C_END

#endif	// __SBCSP_H__
